package com.appengine.paranoid_android.lost;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;

public class InfoService extends Service {
  private static final boolean DEBUG = false;
  private static final String TAG = "Info.Service";
  private static final String NEXT_ALARM = "nextAlarm";

  private SharedPreferences mPreferences;
  private String mNextAlarm;
  private int mCounter;

  // Ensures the info message gets set whenever the screen gets turned on or off. In theory it should be enough to
  // set the message only after the screen is turned on but that can cause any previous value (i.e. actual alarm info)
  // to be displayed for a fraction of a second before it gets overwritten.
  class ScreenOnOffReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      if (DEBUG) Log.d(TAG, "InfoService.ScreenOnOffReceiver.onReceive() called.");
      if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
        setInfoMessage(false);
        if (DEBUG) Log.d(TAG, "Screen is on.");
      } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
        setInfoMessage(true);
        if (DEBUG) Log.d(TAG, "Screen is off.");
      } else {
        if (DEBUG) Log.w(TAG, "Unexpected intent " + intent);
      }
    }
  }

  @Override
  public void onCreate() {
    if (DEBUG) Log.d(TAG, "Starting up.");

    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    registerReceiver(new ScreenOnOffReceiver(), filter);

    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    mNextAlarm = mPreferences.getString(NEXT_ALARM, null);
    mPreferences.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
      @Override
      public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (DEBUG) Log.d(TAG, "Preference changed: " + key);
        if (key == InfoSetup.MESSAGE_KEY) {
          // As far as we know the screen is turned on.
          setInfoMessage(false);
        }
      }
    });

    // Only call this after everything else has been set up.
    setInfoMessage(false);

    super.onCreate();
  }

  protected void setInfoMessage(boolean screenLocking) {
    if (DEBUG) Log.d(TAG, "setInfoMessage");

    String message = mPreferences.getString(InfoSetup.MESSAGE_KEY, null);
    if (message == null) {
      // There is no message to set.
      return;
    }

    // If the message changed in the meantime and it's only one line of text, it's quite likely that it's an actual
    // alarm, so prepend it to the contact info.
    String nextAlarm = Settings.System.getString(getContentResolver(), Settings.System.NEXT_ALARM_FORMATTED);
    if (nextAlarm != null && nextAlarm.contains(message)) {
      if (DEBUG) Log.d(TAG, "Message already displayed. Exiting.");
      return;
    }
    if (nextAlarm == null || nextAlarm.indexOf('\n') == -1) {
      if ((mNextAlarm == null && nextAlarm != null) || mNextAlarm != null && !mNextAlarm.equals(nextAlarm)) {
        if (DEBUG) Log.d(TAG, "Next alarm: " + nextAlarm);
        mNextAlarm = nextAlarm;
        SharedPreferences.Editor edit = mPreferences.edit();
        edit.putString(NEXT_ALARM, nextAlarm);
        edit.commit();
      }
    }

    if (mNextAlarm != null && mNextAlarm.length() > 0) {
      message = String.format("%s\n\n%s", mNextAlarm, message);
    }
    if (DEBUG) {
      message +=  (++mCounter);
      Log.d(TAG, "Set next alarm to: " + message);
    }
    Settings.System.putString(getContentResolver(),
                              Settings.System.NEXT_ALARM_FORMATTED,
                              message);
    if (DEBUG) Log.d(TAG, "Next alarm was set to: " +
                     Settings.System.getString(getContentResolver(), Settings.System.NEXT_ALARM_FORMATTED));

    if (!message.equals(nextAlarm) && screenLocking) {
      if (DEBUG) Log.d(TAG, nextAlarm);
      // The alarm message changed, force the lock screen to update.
      forceLockScreenUpdate();
    }
  }

  protected void forceLockScreenUpdate() {
    // Seems to be the only way of forcing the lock screen to update: disable and reenable the keyguard.
    // Furthermore, disabling then quickly reenabling the lockscreen seems to cause some sort of deadlock, so
    // this has to be done carefully.
    Intent keyguard_hack = new Intent(InfoService.this, LockScreenUpdater.class);
    keyguard_hack.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_FROM_BACKGROUND);
    startActivity(keyguard_hack);
  }

  @Override
  public IBinder onBind(Intent intent) {
    // No interface to bind to.
    return null;
  }
}
